<?php
namespace Lavender\Dao;

use Lavender\Core;
use Lavender\Dao\Exception as DaoException;
use Lavender\Db\RedisConnect;
use Lavender\Errno;
use Lavender\Exception;

abstract class RedisTable
{
	protected $table = 'test';
	protected static $cache = null;
	protected $prefix = '';
	public $is_sync = false; //默认关闭同步

	protected static $instances = array();

	public function __construct()
	{

	}

    /**
     * @return \Lavender\Dao\RedisTable
     */
	public static function instance()
	{
		$class = get_called_class();
		if (empty(self::$instances[$class])) {
			self::$instances[$class] = new $class();
		}
		return self::$instances[$class];
	}

    public function makeKey($id)
    {
        if(empty($this->prefix))
        {
            $this->prefix = L_APP_NAME;
        }
        return  $this->prefix."::".$id;
    }

    /**
     * 取JSON String 以外的值
     *
     * @param [type] $id
     * @return void
     */
    public function getRaw($id){
        $key = $this->makeKey($id);
        return $this->get_handle()->get($key);
    }

    /**
     * 存JSON String 以外的值
     *
     * @param [type] $id
     * @param [type] $data
     * @param [type] $ex
     * @return void
     */
    public function setRaw($id,$data,$ex = null){
        $key = $this->makeKey($id);
		if($ex !== null && is_numeric($ex)){
			$result = $this->get_handle()->set($key,$data,'EX',$ex);
		}
        else
        {
            $result = $this->get_handle()->set($key,$data);
        }
		return $result;
    }

    // set String
	public function set($id, $data, $time = null)
	{
        if(is_array($data)){
            return $this->setJSON($id, $data, $time);
        }
        else{
            return $this->setRaw($id, $data, $time);
        }		
	}
	
	// get String
	public function get($id)
	{
		$data = $this->getRaw($id);
        if($data !== null){
            if(is_string($data)){
                if($data[0] == '[' || $data[0] == '{'){
                    return $this->unpack($data);
                }
            }            
        }
        return $data;
	}

    // get String
    public function getJSON($id)
    {
        $key = $this->makeKey($id);
        $json_value = $this->get_handle()->get($key);
        if ($json_value) {
            $value = $this->unpack($json_value, true);
            return $value;
        }
        return null;
    }

	// set String
	public function setJSON($id, $data, $time = null)
	{
        $key = $this->makeKey($id);
		$json_value = $this->pack($data);
		if($time !== null && is_numeric($time)){
			$result = $this->get_handle()->set($key,$json_value,'EX',$time);
		}
        else
        {
            $result = $this->get_handle()->set($key,$json_value);
        }
		return $result;
	}

    public function delete($id)
    {
        $key = $this->makeKey($id);
        return $this->get_handle()->del($key);
    }

    public function __call($name, $params)
    {
        return $this->get_handle()->__call($name,$params);
    }

    public function execute($name, $params)
    {
        return $this->get_handle()->__call($name,$params);
    }

	// json encode
    public function pack($data)
	{
		return json_encode($data, JSON_UNESCAPED_UNICODE);
	}

	// json decode
    public function unpack($data)
	{
		return json_decode($data, true);
	}

    /**
     * @return \Lavender\Db\RedisConnect
     * @throws \Lavender\Exception
     */
    protected function get_handle()
    {
        $config = Core::get_config('cache', $this->table);
        $hash = md5(json_encode($config,JSON_UNESCAPED_UNICODE)); 
        if(!isset(self::$cache[$hash]) || self::$cache[$hash])
        {
            $hostname = $config['host'];
            $port = $config['port'];
            $database = isset($config['database'])?$config['database']:0;
            $password = isset($config['password'])?$config['password']:null;
            $connectionTimeout = isset($config['connectionTimeout'])?$config['connectionTimeout']:null;
            $dataTimeout = isset($config['dataTimeout'])?$config['dataTimeout']:null;  
            self::$cache[$hash] = new RedisConnect($hostname,$port,$password,$database,$connectionTimeout,$dataTimeout);
        }
        return self::$cache[$hash];
    }

	public static function formatHGetAll($data,$isJsonValue = false){
        $size = count($data);
        if($size < 1){
            return [];
        }
        if($size % 2 !== 0){
            throw new DaoException("format hgetall data error .  data is '".json_encode($data)."'");
        }

        $res = [];
        for($i =0; $i< $size ;$i+=2){
            $key = $data[$i];
            $val = $data[$i+1];
            if($isJsonValue){
                $val = @json_decode($val,true);
            }
            $res[$key] = $val;
        }
        return $res;
    }


}